#! /usr/bin/env ruby

require 'optparse'

$opts = {
  :idy => 98,
  :verbose => 0,
}

parser = OptionParser.new do |o|
  o.banner = "Usage: $0 SrNamesFile CoordsFile SR [SR ...]"

  o.on("-i", "--idy", "Min identity") { |v|
    $opts[:idy] = v.to_f
  }

  o.on("-v", "--verbose", "Be verbose. More -v for more verbosity") { |v|
    $opts[:verbose] += 1
  }

  o.on_tail("-h", "--help", "This message") {
    puts(o)
    exit(0)
  }
end
parser.parse!

sr_names_file = ARGV.shift
coords_file = ARGV.shift

def die msg
  STDERR.puts msg
  exit(1)
end

def print_history(history, index, id2names)
  history.each { |h|
    h2 = h[index].clone
    h2[-1] = id2names[h2[-1]]
    puts(h2.join(" "))
  }
end

die(parser) if sr_names_file.nil? || coords_file.nil? || ARGV.size == 0

# Get for each super read name the corresponding ID
super_reads_id = {}

ARGV.each { |sr| super_reads_id[sr] = nil }

open(sr_names_file) { |fd|
  fd.lines.each_with_index { |l, i|
    l.chomp!
    super_reads_id[l] = i if super_reads_id.has_key?(l)
  }
}

id_super_reads = {}
super_reads_id.each { |name, id|
  die("Invalid super read name '#{name}'") if id.nil?
  id_super_reads[id] = name
}

# Load all the matches corresponding to these super reads. Mapping is
# 0=>S1, 1=>E1, 2=>S2, 3=>E2, 4=>LEN1, 5=>LEN2, 6=>IDY, 7=>LENR,
# 8=>LENQ, 9=>QUERY, 10=>REF
matches = Hash.new { |h, sr_name| h[sr_name] = [] }
open(coords_file) { |fd|
  4.times { fd.gets } # Skip header
  fd.each_line { |l|
    match = l.split
    name = id_super_reads[match[-1].to_i]
    next if name.nil?
    match = [match[0].to_i, match[1].to_i, match[2].to_i, match[3].to_i, match[4].to_i, match[5].to_i,
             match[6].to_f, match[7].to_i, match[8].to_i, match[11], match[12].to_i]
    next if match[6] < $opts[:idy]
    matches[name] << match
  }
}

current_matches = matches[ARGV[0]]
die("No matches for starting super read '#{ARGV[0]}'") if current_matches.empty?

matches_history = []
matches_history << current_matches
terminated = {} # index of matching paths that terminated

ARGV[1..-1].each { |sr_name|
  new_matches = matches[sr_name]
  new_current_matches = []
  new_matches.each { |match|
    # If this match overlaps a current match, we keep it. Only check
    # for the same chromosome and dove tail overlap. Proper
    # orientation is not taken into account yet.
    current_matches.each_with_index { |cmatch, i|
      next if cmatch.nil?
      if cmatch[9] == match[9] && # Same chromosome
          (match[0] < cmatch[1] && cmatch[0] < match[1]) # Overlap
        new_current_matches[i] = match
      end
    }
  }

  if $opts[:verbose] > 1
    new_current_matches.each_with_index { |x, i|
      if x.nil? && !terminated[i]
        puts("Partial match:")
        print_history(matches_history, i, id_super_reads)
        terminated[i] = true
      end
    }
  end
  break if new_current_matches.empty? || new_current_matches.all? { |x| x.nil? }
  current_matches = new_current_matches
  matches_history << current_matches
}

die("No proper alignment found") if matches_history.size < ARGV.size

if $opts[:verbose] > 0
  puts("Complete match:")
  print_history(matches_history, current_matches.find_index { |x| !x.nil? }, id_super_reads)
end
exit(0)
